using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Modeling.Diagrams;

namespace Evaluant.EussDSL
{
    class MultiplicityVerifier
    {
        /// <summary>
        /// Detects the multiplicity of a reference. The 3 possibilities are 1..1, 1..*, *..*.
        /// Other multiplicities remains unknown, but not considered as invalid.
        /// </summary>
        /// <param name="rns">The shape of the reference</param>
        /// <param name="newParentFieldValue">The new parentField value</param>
        /// <param name="newChildFieldValue">The new childField value</param>
        public static void VerifyReferenceNew(ReferenceNewShape rns, string newParentFieldValue, string newChildFieldValue)
        {
            bool foundId = false;
            string newValue = null, newValue2 = null;
            switch (((ReferenceNew)(rns.ModelElement)).RulesNew.Count)
            {
                case 1: // potentially a 1..1 or 1..* relationship
                    newValue = (newParentFieldValue == null) ? ((ReferenceNew)(rns.ModelElement)).RulesNew[0].parentField : newParentFieldValue;
                    foreach (Identifier id in ((ReferenceNew)(rns.ModelElement)).Entity.Identifiers)
                    {
                        if (id.field == newValue)
                        {
                            foundId = true;
                        }
                    }
                    if (foundId)
                    { // 1..* relationship
                        foreach (LinkShape ls in rns.Link)
                        {
                            if (ls is SourceNewConnector)
                            {
                                ((SourceNewConnector)ls).Multiplicity = "1";
                            }
                            if (ls is TargetNewConnector)
                            { // The TargetNewConnector has been created manually : it's the same for its decorator
                                AssociatedPropertyInfo propertyInfo = new AssociatedPropertyInfo(TargetNewConnector.MultiplicityDomainPropertyId);
                                propertyInfo.IsShapeProperty = true;
                                ((TargetNewConnector)ls).FindDecorator("MultiplicityDecorator").AssociateValueWith(((TargetNewConnector)ls).Store, propertyInfo);
                                ((TargetNewConnector)ls).Multiplicity = "*";
                            }
                        }
                    }
                    else
                    { // 1..1 relationship
                        foreach (LinkShape ls in rns.Link)
                        {
                            if (ls is SourceNewConnector)
                            {
                                ((SourceNewConnector)ls).Multiplicity = "1";
                            }
                            if (ls is TargetNewConnector)
                            { // The TargetNewConnector has been created manually : it's the same for its decorator
                                AssociatedPropertyInfo propertyInfo = new AssociatedPropertyInfo(TargetNewConnector.MultiplicityDomainPropertyId);
                                propertyInfo.IsShapeProperty = true;
                                ((TargetNewConnector)ls).FindDecorator("MultiplicityDecorator").AssociateValueWith(((TargetNewConnector)ls).Store, propertyInfo);
                                ((TargetNewConnector)ls).Multiplicity = "1";
                            }
                        }
                    }
                    break;
                case 2: // potentially a *..* relationship
                    // one rule must have a parentField equals to an identifier field of the parent
                    // there are 2 RuleNew in element.ReferenceNew
                    newValue = (newParentFieldValue == null) ? ((ReferenceNew)(rns.ModelElement)).RulesNew[0].parentField : newParentFieldValue;
                    newValue2 = (newChildFieldValue == null) ? ((ReferenceNew)(rns.ModelElement)).RulesNew[1].childField : newChildFieldValue;

                    if (!TestWith2Rules(rns, newValue, newValue2))
                    {
                        newValue = (newParentFieldValue == null) ? ((ReferenceNew)(rns.ModelElement)).RulesNew[1].parentField : newParentFieldValue;
                        newValue2 = (newChildFieldValue == null) ? ((ReferenceNew)(rns.ModelElement)).RulesNew[0].childField : newChildFieldValue;

                        TestWith2Rules(rns, newValue, newValue2);
                    }
                    break;
                default: // unknown relationship
                    foreach (LinkShape ls in rns.Link)
                    {
                        if (ls is SourceNewConnector)
                        {
                            ((SourceNewConnector)ls).Multiplicity = "";
                        }
                        if (ls is TargetNewConnector)
                        { // The TargetNewConnector has been created manually : it's the same for its decorator
                            AssociatedPropertyInfo propertyInfo = new AssociatedPropertyInfo(TargetNewConnector.MultiplicityDomainPropertyId);
                            propertyInfo.IsShapeProperty = true;
                            ((TargetNewConnector)ls).FindDecorator("MultiplicityDecorator").AssociateValueWith(((TargetNewConnector)ls).Store, propertyInfo);
                            ((TargetNewConnector)ls).Multiplicity = "";
                        }
                    }
                    break;
            }
        }

        private static bool TestWith2Rules(ReferenceNewShape rns, string newValue, string newValue2)
        {
            bool foundIdIndex = false, foundChildField = false;
            bool result = false;

            foreach (Identifier id in ((ReferenceNew)(rns.ModelElement)).Entity.Identifiers)
            {
                if (newValue == id.field)
                {
                    foundIdIndex = true;
                }
            }

            // the other rule must have a childField equals to an identifier of a target
            foreach (LinkShape ls in rns.Link)
            {
                if (ls is TargetNewConnector)
                {
                    Entity toEntity = (Entity)(((TargetNewConnector)ls).ToShape.ModelElement);
                    foreach (Identifier id in toEntity.Identifiers)
                    {
                        if (newValue2 == id.field)
                        {
                            foundChildField = true;
                        }
                    }
                }
            }

            if (foundIdIndex && foundChildField)
            {
                foreach (LinkShape ls in rns.Link)
                {
                    if (ls is SourceNewConnector)
                    {
                        ((SourceNewConnector)ls).Multiplicity = "*";
                    }
                    if (ls is TargetNewConnector)
                    { // The TargetNewConnector has been created manually : it's the same for its decorator
                        AssociatedPropertyInfo propertyInfo = new AssociatedPropertyInfo(TargetNewConnector.MultiplicityDomainPropertyId);
                        propertyInfo.IsShapeProperty = true;
                        ((TargetNewConnector)ls).FindDecorator("MultiplicityDecorator").AssociateValueWith(((TargetNewConnector)ls).Store, propertyInfo);
                        ((TargetNewConnector)ls).Multiplicity = "*";
                    }
                }
                result = true;
            }
            else
            {
                foreach (LinkShape ls in rns.Link)
                {
                    if (ls is SourceNewConnector)
                    {
                        ((SourceNewConnector)ls).Multiplicity = "";
                    }
                    if (ls is TargetNewConnector)
                    { // The TargetNewConnector has been created manually : it's the same for its decorator
                        AssociatedPropertyInfo propertyInfo = new AssociatedPropertyInfo(TargetNewConnector.MultiplicityDomainPropertyId);
                        propertyInfo.IsShapeProperty = true;
                        ((TargetNewConnector)ls).FindDecorator("MultiplicityDecorator").AssociateValueWith(((TargetNewConnector)ls).Store, propertyInfo);
                        ((TargetNewConnector)ls).Multiplicity = "";
                    }
                }
                result = false;
            }
            return result;
        }
    }
}
